library ieee;

use ieee.std_logic_1164.all;

use ieee.numeric_std.all;
use work.typeDefinitions.all;


entity dcacheSet is port(
  clk, nrst : in std_logic;

  tag_in1   : in std_logic_vector(24 downto 0);
  data_in   : in std_logic_vector(63 downto 0);
  index_in1 : in std_logic_vector(3 downto 0);

  tag_in2   : in std_logic_vector(24 downto 0);
  index_in2 : in std_logic_vector(3 downto 0);


  cohere_in1  : in coherenceState;
  cohere_in2  : in coherenceState;
  cohere_wen1 : in std_logic;
  cohere_wen2 : in std_logic;


  recent_in : in std_logic;
  dirty_in  : in std_logic;

  recent_wen : in std_logic;

  data_wen : in std_logic;

  data_out1 : out std_logic_vector(63 downto 0);
  data_out2 : out std_logic_vector(63 downto 0);


  tag_out : out std_logic_vector(24 downto 0);

  hit1 : out std_logic;
  hit2 : out std_logic;

  cohere_out1 : out coherenceState;
  dirty1      : out std_logic;

  cohere_out2 : out coherenceState;
  dirty2      : out std_logic;
  multWrite   : out std_logic;

  recent : out std_logic);
end dcacheSet;



architecture data_cache of dcacheSet is
  type   ram is array(15 downto 0) of std_logic_vector(63 downto 0);
  type   tagg is array(15 downto 0) of std_logic_vector(24 downto 0);
  type   recentd is array(15 downto 0) of std_logic;
  type   dirtyd is array(15 downto 0) of std_logic;
  type   cohered is array(15 downto 0) of coherenceState;
  signal ram1, ram2       : ram;
  signal tagg1, tagg2     : tagg;
  signal recent1, recent2 : recentd;
  signal t_dirty1, t_dirty2   : dirtyd;
  signal cohere1, cohere2 : cohered;

begin
  regg : process(clk, nrst)
  begin
    if nrst = '0' then
      for i in 0 to 15 loop
        t_dirty1(i)   <= '0';
        recent1(i)  <= '0';
        ram1(i)     <= (others => '0');
        tagg1(i)    <= (others => '0');
        cohere1(i)  <= co_I;
      end loop;

    elsif falling_edge(clk) then
      for i in 0 to 15 loop
        t_dirty1(i)  <= t_dirty2(i);
        recent1(i) <= recent2(i);
        ram1 (i)   <= ram2(i);
        tagg1(i)   <= tagg2(i);
        cohere1(i) <= cohere2(i);
      end loop;

    end if;
  end process regg;

  nextstate : process(ram1, recent1, cohere1, cohere_in1, cohere_wen1, cohere_wen2, cohere_in2, t_dirty1, tagg1, tag_in1, tag_in2, data_in, dirty_in, data_wen, recent_in, recent_wen, index_in1, index_in2)
    variable var1, var2 : integer range 0 to 15;
  begin
    
    var1 := to_integer(unsigned(index_in1));
    var2 := to_integer(unsigned(index_in2));

    for i in 0 to 15 loop
      tagg2(i)   <= tagg1(i);
      ram2(i)    <= ram1(i);
      recent2(i) <= recent1(i);
      t_dirty2(i)  <= t_dirty1(i);
      cohere2(i) <= cohere1(i);
    end loop;

    if data_wen = '1' then
      tagg2(var1)  <= tag_in1;
      ram2(var1)   <= data_in;
      t_dirty2(var1) <= dirty_in;
    end if;

    if(var1 = var2) then
      multWrite <= '1';
      if(cohere_wen1 = '1') then
        cohere2(var1) <= cohere_in1;
      end if;
    else
      multWrite <= '0';
      if(cohere_wen1 = '1') then
        cohere2(var1) <= cohere_in1;
      end if;
      if(cohere_wen2 = '1') then
        cohere2(var2) <= cohere_in2;
      end if;

    end if;

    if recent_wen = '1' then
      recent2(var1) <= recent_in;
    end if;

    cohere_out2 <= cohere1(var2);
    data_out2   <= ram1(var2);
    dirty2      <= t_dirty1(var2);

    if (tag_in2 = tagg1(var2)) and (cohere1(var2) = co_S or cohere1(var2) = co_M) then
      hit2 <= '1';
    else
      hit2 <= '0';
    end if;


    cohere_out1 <= cohere1(var1);
    data_out1   <= ram1(var1);
    tag_out     <= tagg1(var1);
    recent      <= recent1(var1);
    dirty1      <= t_dirty1(var1);

    if (tag_in1 = tagg1(var1)) and (cohere1(var1) = co_S or cohere1(var1) = co_M) then
      hit1 <= '1';
    else
      hit1 <= '0';
    end if;
    
  end process nextstate;
end;

